package com.example.demo.core;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 动态加载 class 文件 工具类
 */
public class DynamicLoadUtil {

    /**
     * 加载外部 class 文件信息
     *
     * @param filePath        指定文件目录信息
     * @param beanClassLoader 类加载信息
     * @return 返回需加载的class文件信息
     */
    public static List<Class> loadClass(String filePath, ClassLoader beanClassLoader) {
        List<Class> classNameList = new ArrayList<>();
        File clazzPath = new File(filePath);
        int clazzCount = 0;
        if (clazzPath.exists() && clazzPath.isDirectory()) {
            int clazzPathLen = clazzPath.getAbsolutePath().length() + 1;
            Stack<File> stack = new Stack<>();
            stack.push(clazzPath);
            while (stack.isEmpty() == false) {
                File path = stack.pop();
                File[] classFiles = path.listFiles(file -> file.isDirectory() || file.getName().toLowerCase().endsWith(".class"));
                for (File subFile : classFiles) {
                    if (subFile.isDirectory()) {
                        stack.push(subFile);
                    } else {
                        if (clazzCount++ == 0) {
                            Method method = null;
                            try {
                                method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
                            } catch (NoSuchMethodException e) {
                                e.printStackTrace();
                            }
                            boolean accessible = method.isAccessible();
                            try {
                                if (accessible == false) {
                                    method.setAccessible(true);
                                }
                                addURL(subFile,beanClassLoader);
                            } finally {
                                method.setAccessible(accessible);
                            }
                        }
                        String className = subFile.getAbsolutePath();
                        className = className.substring(clazzPathLen, className.length() - 6);
                        className = className.replace(File.separatorChar, '.');
                        try {
                            classNameList.add(beanClassLoader.loadClass(className));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return classNameList;
    }


    /**
     * 初始化 addUrl 方法.
     *
     * @return 可访问addUrl方法的Method对象
     */
    private static Method initAddMethod() {
        try {
            Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
            add.setAccessible(true);
            return add;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 循环遍历目录，找出所有的jar包。
     *
     * @param filePath 当前遍历文件
     */
    public static void loopJarToClassPath(String filePath, ClassLoader beanClassLoader) {
        File clazzPath = new File(filePath);
        File[] classFiles = clazzPath.listFiles(file -> file.getName().toLowerCase().endsWith(".jar"));
        if (null != classFiles) {
            for (File subFile : classFiles) {
                System.out.println("subFile--->" + subFile.getPath());
                addURL(subFile, beanClassLoader);
            }
        }
    }

    /**
     * 通过filepath加载文件到classpath。
     *
     * @return URL
     * @throws Exception 异常
     */
    private static void addURL(File file, ClassLoader beanClassLoader) {
        try {
            initAddMethod().invoke(beanClassLoader, new Object[]{file.toURI().toURL()});
        } catch (Exception e) {

        }
    }

}